//
// Created by syj on 2023/7/26.
//

#ifndef SPDLOG_TEST_MLOG_IMPL_H
#define SPDLOG_TEST_MLOG_IMPL_H

#include <iostream>
//#include <string>
#include "spdlog/sinks/rotating_file_sink.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/async.h"
#include "spdlog/sinks/basic_file_sink.h"
#include "spdlog/spdlog.h"

//#include "cJSON/cJSON.h"

namespace mlogimpl
{
    enum class LoggerLevel : uint8_t
    {
        trace = 0,
        debug,
        info,
        warn ,
        err ,
        critical ,
        off ,
        n_levels /* 7 */
    };

    typedef struct __LoggerConfig__
    {
        char module_name[32] = {0}; /* 进程名字 */
        char root_path[64]{"./"}; /* 文件路径 */
        char file_size[16]{"200k"}; /* 文件大小 */
        uint16_t file_num = 3; /* 文件个数,最小为 1 */
        LoggerLevel file_level{LoggerLevel::warn}; /* 文件输出等级 */
        LoggerLevel console_level{LoggerLevel::warn}; /* 文件输出等级 */
    }LoggerConfig;

    class Logger final
    {
        using SpdLogPtr=std::shared_ptr<spdlog::logger>;
        using SinkPtr=std::shared_ptr<spdlog::sinks::sink>;
    private:
        Logger();
        Logger(const Logger&) = delete;
        Logger( Logger&&) = delete;
        Logger &operator=(const Logger&) = delete;
        Logger &operator=( Logger&&) = delete;
    public:
        static Logger * Instance()
        {
            static Logger a;
            return &a;
        }

        ~Logger();

        template<typename... Args>
        void Trace(const char * file, const int line, const char* func, Args &&... args);
        template<typename... Args>
        void Debug(const char * file, const int line, const char* func, Args &&... args);
        template<typename... Args>
        void Info(const char * file, const int line, const char* func, Args &&... args);
        template<typename... Args>
        void Warn(const char * file, const int line, const char* func, Args &&... args);
        template<typename... Args>
        void Error(const char * file, const int line, const char* func, Args &&... args);
        template<typename... Args>
        void Critical(const char * file, const int line, const char* func, Args &&... args);
#if 0
        void Init(const std::string file, const std::string name = "default");
#else
        void Init(const LoggerConfig&);
#endif
    protected:
        template<typename... Args>
        void Log(const char * file, const int line, const char* func,
                 const spdlog::level::level_enum level, Args &&... args);

        size_t ParseFileSize(const std::string&);
//        void SetLogLevel(const SinkPtr&, const std::string&);
        void SetLogLevel(const SinkPtr&, const LoggerLevel&);

    private:
        SpdLogPtr pLogger;
#if 0
        cJSON * node{nullptr};
#endif
    };

    template<typename... Args>
    void Logger::Log(const char * file, const int line, const char* func,
             const spdlog::level::level_enum level, Args &&... args)
    {
        try {
            pLogger->log(spdlog::source_loc{file,line,func}, level,std::forward<Args>(args)...);
            pLogger->flush();
        }
        catch (const spdlog::spdlog_ex & ex)
        {
            SPDLOG_WARN("Log spdlog::spdlog_ex error! {}", ex.what());
        }
    }

    template<typename... Args>
    void Logger::Trace(const char * file, const int line, const char* func, Args &&... args)
    {
        try {
            pLogger->log(spdlog::source_loc{file,line,func}, spdlog::level::trace,std::forward<Args>(args)...);
            pLogger->flush_on(spdlog::level::trace);
        }
        catch (const spdlog::spdlog_ex & ex)
        {
            SPDLOG_WARN("Log spdlog::spdlog_ex error! {}", ex.what());
        }
    }
    template<typename... Args>
    void Logger::Debug(const char * file, const int line, const char* func, Args &&... args){
        try {
            pLogger->log(spdlog::source_loc{file,line,func}, spdlog::level::debug,std::forward<Args>(args)...);
            pLogger->flush_on(spdlog::level::debug);
        }
        catch (const spdlog::spdlog_ex & ex)
        {
            SPDLOG_WARN("Log spdlog::spdlog_ex error! {}", ex.what());
        }
    }
    template<typename... Args>
    void Logger::Info(const char * file, const int line, const char* func, Args &&... args){
        try {
            pLogger->log(spdlog::source_loc{file,line,func}, spdlog::level::info,std::forward<Args>(args)...);
            pLogger->flush_on(spdlog::level::info);
        }
        catch (const spdlog::spdlog_ex & ex)
        {
            SPDLOG_WARN("Log spdlog::spdlog_ex error! {}", ex.what());
        }
    }
    template<typename... Args>
    void Logger::Warn(const char * file, const int line, const char* func, Args &&... args){
        try {
            pLogger->log(spdlog::source_loc{file,line,func}, spdlog::level::warn,std::forward<Args>(args)...);
            pLogger->flush_on(spdlog::level::warn);
        }
        catch (const spdlog::spdlog_ex & ex)
        {
            SPDLOG_WARN("Log spdlog::spdlog_ex error! {}", ex.what());
        }
    }
    template<typename... Args>
    void Logger::Error(const char * file, const int line, const char* func, Args &&... args){
        try {
            pLogger->log(spdlog::source_loc{file,line,func}, spdlog::level::err,std::forward<Args>(args)...);
            pLogger->flush_on(spdlog::level::err);
        }
        catch (const spdlog::spdlog_ex & ex)
        {
            SPDLOG_WARN("Log spdlog::spdlog_ex error! {}", ex.what());
        }
    }
    template<typename... Args>
    void Logger::Critical(const char * file, const int line, const char* func, Args &&... args){
        try {
            pLogger->log(spdlog::source_loc{file,line,func}, spdlog::level::critical,std::forward<Args>(args)...);
            pLogger->flush_on(spdlog::level::critical);
        }
        catch (const spdlog::spdlog_ex & ex)
        {
            SPDLOG_WARN("Log spdlog::spdlog_ex error! {}", ex.what());
        }
    }
}


#endif //SPDLOG_TEST_MLOG_IMPL_H
